﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Script.Services;
using System.Web.UI;
using System.Web.UI.WebControls;
using GPC_Overlay;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.StorageClient; 
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using System.Threading.Tasks;
using System.Text;

namespace GISWebRole
{

    public partial class _Default : System.Web.UI.Page
    {

        private enum BalancingScheme { None, LargestFirst, RowOrder, ColumnOrder }

        private string _map1;
        private string _map2;
        private string _op;
        private GpcOperation _operator;
        public CloudStorageAccount _account;
        public string connectionString;
        public static int concurrencyLimit = 8;
        public static int currentOps = 0;
        public static int processed = 0;
        public static int toprocess = 0;
        public static List<string> blobs;
        public static List<Polygon> basePoly;
        public static List<Polygon> overlayPoly;

        protected void Page_Load(object sender, EventArgs e)
        {
            connectionString = RoleEnvironment.GetConfigurationSettingValue("DataConnectionString");
            _account = CloudStorageAccount.Parse(connectionString);
            if (!IsPostBack)
            {
                BlobHelper blobObject = new BlobHelper(connectionString);
                _setupDropDownLists(blobObject);
            }
        }

        private void _setupDropDownLists(BlobHelper blobObject)
        {

            CloudBlobContainer container = blobObject.BlobClient.GetContainerReference(DataConstants.MAP_CONTAINER_BLOB);
            CloudBlobDirectory dir = container.GetDirectoryReference("./");
            List<string> maps = (from map in dir.ListBlobs() select Path.GetFileName(map.Uri.AbsolutePath)).ToList();
            List<string> maps2 = (from map in maps select map).ToList();

            Array ops = Enum.GetValues(typeof(GpcOperation));

            Array schemes = Enum.GetValues(typeof(BalancingScheme));

            foreach (string filename in maps)
            {
                ddlMap1.Items.Add(filename);
                ddlMap2.Items.Add(filename);
            }
            foreach (object op in ops)
            {
                ddlOperator.Items.Add(op.ToString());
            }
        }

        public string Overlay(string map1, string map2, string op)
        {
                string rslt = _saveResult(); 
                System.Diagnostics.Trace.WriteLine("GISWebRole done overlay Job" + DateTime.Now.ToString(), "Information");
                System.Diagnostics.Trace.WriteLine("Result:" + rslt, "Information");
                return rslt;
        }

        public void assignWork(string map1, string map2, string op)
        {
            BlobHelper blobObject = new BlobHelper(RoleEnvironment.GetConfigurationSettingValue("DataConnectionString"));
            QueueHelper QueueObject = new QueueHelper(RoleEnvironment.GetConfigurationSettingValue("DataConnectionString"));

            StringBuilder result = new StringBuilder();

            blobObject.DeleteBlob(DataConstants.MAP_CONTAINER_BLOB, "result.xml");

            /* Write the start of XML doc */
            result.AppendLine("<gml:FeatureCollection");

            result.AppendLine(" xmlns:gml=" + '"' + "http://www.opengis.net/gml" + '"');
            result.AppendLine(" xmlns:xlink=" + '"' + "http://www.w3.org/1999/xlink" + '"');
            result.AppendLine(" xmlns:xsi=" + '"' + "http://www.w3.org/2001/XMLSchema-instance" + '"');
            result.AppendLine(" xmlns:fme=" + '"' + "http://www.safe.com/gml/fme" + '"');
            result.AppendLine(" xsi:schemaLocation=" + '"' + "http://www.safe.com/gml/output.xsd>" + '"');
            BlobHelper.PutBlock(connectionString, DataConstants.MAP_CONTAINER_BLOB, DataConstants.OUTPUT_BLOB, Guid.NewGuid().ToString(), result.ToString());

            try
            {
                System.Diagnostics.Trace.WriteLine("GISWebRole doing overlay Job" + DateTime.Now.ToString(), "Information");
                QueueObject.ClearMessages(DataConstants.INPUT_PARAS);
                QueueHelper.PutMessageStatic(RoleEnvironment.GetConfigurationSettingValue("DataConnectionString"), DataConstants.INPUT_PARAS, new CloudQueueMessage(map1 + "[" + map2 + "[" + op));
            }
            catch (Exception exp)
             {
                 System.Diagnostics.Trace.Write(exp.Message);
                 
             }
        }

        public string checkProgress()
        {
            int finishMessages = 0;
            int parsingCount = 0;
            int totalPolygons = 0;
            string rslt = string.Empty;
            CloudQueueMessage msg = new CloudQueueMessage("");
            QueueHelper queue = new QueueHelper(connectionString);

            int numberOfWorkers = RoleEnvironment.Roles["GISWorkerRole"].Instances.Count;
            queue.GetApproxMessageCount(DataConstants.BLOB_COUNT, out parsingCount);
            if (parsingCount == 0)
            {
                return "Crayons is sending the input files to workers.";
            }

            if (parsingCount > 0)
            {
                queue.PeekMessage(DataConstants.BLOB_COUNT, out msg);
                totalPolygons = int.Parse(msg.AsString);

                if (parsingCount < numberOfWorkers)
                {
                    if (parsingCount == 1)
                    {
                        rslt = "Crayons has successfully sent files to " + parsingCount.ToString() + " worker and the worker is now parsing the files. ";
                    }
                    else
                    {
                        rslt = "Crayons has successfully sent files to " + parsingCount.ToString() + " workers and workers are now parsing the files. ";
                    }
                }

                else if (parsingCount == numberOfWorkers)
                {
                    rslt = "All workers have finished file handling process. ";
                } 
            }

            queue.GetApproxMessageCount(DataConstants.RESULT_QUEUE, out finishMessages);

            if (finishMessages > 0)
            {
                rslt += finishMessages.ToString() + " out of " + totalPolygons.ToString() + " polygons have been processed.";

                if (finishMessages == totalPolygons)
                {
                    rslt = "Processing is over, Crayons is now getting you the results.";
                   
                }
            }
            return rslt;
        }

        private string _saveResult()
        {
            string[] blockIDs;
            int numberOfWorkers = RoleEnvironment.Roles["GISWorkerRole"].Instances.Count;
            string connectionString = RoleEnvironment.GetConfigurationSettingValue("DataConnectionString");
            QueueHelper queue = new QueueHelper(connectionString);

            DateTime startSaveTime = DateTime.Now;
            // rite the end tag for the output ile 
            string outputEndTag = "</gml:FeatureCollection>";
            BlobHelper.PutBlock(connectionString, DataConstants.MAP_CONTAINER_BLOB, DataConstants.OUTPUT_BLOB, Guid.NewGuid().ToString(), outputEndTag);
            // Get the uncommitted blocks 
            BlobHelper.GetBlockList(connectionString, DataConstants.MAP_CONTAINER_BLOB, DataConstants.OUTPUT_BLOB, out blockIDs);
            //Commit the blob 
            BlobHelper.PutBlockList(connectionString, DataConstants.MAP_CONTAINER_BLOB, DataConstants.OUTPUT_BLOB, blockIDs);
            TimeSpan saveTime = DateTime.Now.Subtract(startSaveTime);
            List<CloudQueueMessage> msgs = new List<CloudQueueMessage>();
            IEnumerable<CloudQueueMessage> msg = new List<CloudQueueMessage>();

            CloudQueueMessage timeMsg = new CloudQueueMessage("");
            string strTimeMsg = String.Empty;
            string[] splitTimeMsg;

            float fileDownloadTime = 0;
            float parseTime = 0;
            float graphCreationTime = 0;
            float totalTaskCreationTime = 0;
            float taskUploadingTime = 0;
            float processingTime = 0;
            float taskDownloadingTime = 0;
          
            
            for (int i = 0; i<numberOfWorkers; i++)
            {
               queue.GetMessage(DataConstants.TIME_QUEUE, out timeMsg);

               strTimeMsg = timeMsg.AsString;
               splitTimeMsg = strTimeMsg.Split('{');

               fileDownloadTime         +=      float.Parse(splitTimeMsg[0]);
               parseTime                +=      float.Parse(splitTimeMsg[1]);
               graphCreationTime        +=      float.Parse(splitTimeMsg[2]);
               totalTaskCreationTime    +=      float.Parse(splitTimeMsg[3]);
               taskUploadingTime        +=      float.Parse(splitTimeMsg[4]);
               processingTime           +=      float.Parse(splitTimeMsg[5]);
               taskDownloadingTime      +=      float.Parse(splitTimeMsg[6]);
               queue.DeleteMessage(DataConstants.TIME_QUEUE, timeMsg);
            }

            fileDownloadTime        /= numberOfWorkers;
            parseTime               /= numberOfWorkers;
            graphCreationTime       /= numberOfWorkers;
            totalTaskCreationTime   /= numberOfWorkers;
            taskUploadingTime       /= numberOfWorkers;
            processingTime          /= numberOfWorkers;
            taskDownloadingTime     /= numberOfWorkers;

            queue.ClearMessages(DataConstants.RESULT_QUEUE);
            queue.ClearMessages(DataConstants.INPUT_PARAS);
            queue.ClearMessages(DataConstants.BLOB_COUNT);

            string rsltStr = "File Downloading Time:\r\n" + fileDownloadTime.ToString() + " Seconds\r\nTotal Parsing Time:" +
            parseTime.ToString() + " Seconds\r\nGraph Creation Time:" + graphCreationTime.ToString() + " Seconds\r\nTotal Task Storing time:" +
            totalTaskCreationTime.ToString() + " Seconds\r\n Task Uploading Time:" + taskUploadingTime.ToString() +
            " Seconds\r\n Total Processing Time:" + processingTime.ToString() + " Seconds\r\n Task Downloading time:" + taskDownloadingTime.ToString()
            + " Seconds\nOutput Creation time: " + (saveTime.TotalSeconds).ToString() + " Seconds\n";
            System.Diagnostics.Trace.WriteLine(rsltStr);
            
            return rsltStr + "Download resulting GML file from https://afcrayons.blob.core.windows.net/gpcfiles/result.xml";
        }

        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            //string s = ddlMap1.SelectedValue.ToString();

            _op = _operator.ToString();

            if (_map1 == String.Empty || _map2 == string.Empty || _op == String.Empty)
            {
                txtTimer.Text = "All fields are required. Please select correct valuses and click submit again.";
            }
            else
            {
                assignWork(ddlMap1.Text, ddlMap2.Text, ddlOperator.Text);
            }

            tmrUpdate.Enabled = true;
          
            txtTimer.Visible = true;
            txtTimer.Text = "Crayons is now performing overlay processing on the selected files.";
            btnSubmit.Visible = false;
        }

        protected void ddlMap1_IndexChanged(object sender, EventArgs e)
        {
            _map1 = (ddlMap1.SelectedIndex != -1) ? ddlMap1.SelectedItem.ToString() : string.Empty;
        }

        protected void ddlOperator_IndexChanged(object sender, EventArgs e)
        {
            if (this.ddlOperator.SelectedIndex != -1)
            {
                _operator = (GpcOperation)Enum.Parse(typeof(GpcOperation), this.ddlOperator.SelectedItem.Value);
            }
            else
            {
                _operator = GpcOperation.Union;
            }
        }

        protected void ddlMap2_IndexChanged(object sender, EventArgs e)
        {
            _map2 = (ddlMap2.SelectedIndex != -1) ? ddlMap2.SelectedItem.ToString() : string.Empty;
        }
      
        protected void tmrUpdate_Tick(object sender, EventArgs e)
        {
            txtTimer.Text = checkProgress();
            if (txtTimer.Text == "Processing is over, Crayons is now getting you the results.")
            {
                txtTimer.Text = _saveResult();
                tmrUpdate.Enabled = false;
                cmdReset.Visible = true;
            }
        }

        protected void cmdReset_Click(object sender, EventArgs e)
        {
            txtTimer.Text = "";
            cmdReset.Visible = false;
            btnSubmit.Visible = true;
        }
    }
}

